package middleware

import (
	"fmt"
	"math"
	"os"
	"time"

	"github.com/gin-gonic/gin"
	rotatelogs "github.com/lestrrat-go/file-rotatelogs"
	"github.com/rifflock/lfshook"
	"github.com/sirupsen/logrus"
)

// 日志中间件的相关配置 写入到对应的日志文件中
func Log() gin.HandlerFunc {
	// 日志写入到文件中
	filePath := "log/log"
	//linkName := "log/latest_log.log"
	src, err := os.OpenFile(filePath, os.O_RDWR|os.O_CREATE, 0755)
	if err != nil {
		fmt.Println("err:", err)
	}
	logger := logrus.New()
	// 提供的方法 写入到对应的文件
	logger.Out = src
	// 设置日志级别
	logger.SetLevel(logrus.DebugLevel)
	// 定义日志分割文件
	logWriter, _ := rotatelogs.New(
		// 文件名
		filePath+"%Y%m%d.log",
		// 保存时间
		rotatelogs.WithMaxAge(time.Hour*24*7),
		// 多长时间分割一次
		rotatelogs.WithRotationTime(24*time.Hour),
	// 软连接 指向最新的日志
	//rotatelogs.WithLinkName(linkName),
	)
	// 这里判定什么级别的日志写入到那个对应的文件中
	writeMap := lfshook.WriterMap{
		logrus.InfoLevel:  logWriter,
		logrus.FatalLevel: logWriter,
		logrus.DebugLevel: logWriter,
		logrus.WarnLevel:  logWriter,
		logrus.ErrorLevel: logWriter,
		logrus.PanicLevel: logWriter,
	}
	Hook := lfshook.NewHook(writeMap, &logrus.TextFormatter{
		ForceColors:               false,
		DisableColors:             false,
		ForceQuote:                false,
		DisableQuote:              false,
		EnvironmentOverrideColors: false,
		DisableTimestamp:          false,
		FullTimestamp:             false,
		TimestampFormat:           "2006-01-02-15:04:05",
		DisableSorting:            false,
		SortingFunc:               nil,
		DisableLevelTruncation:    false,
		PadLevelText:              false,
		QuoteEmptyFields:          false,
		FieldMap:                  nil,
		CallerPrettyfier:          nil,
	})
	logger.AddHook(Hook)
	// 洋葱模型 先进后出 栈方式执行 c.Next之后跳到下一个中间件执行
	return func(c *gin.Context) {
		// 请求的访问时间
		startTime := time.Now()
		c.Next()
		stopTime := time.Since(startTime)
		spendTime := fmt.Sprintf("%d ms", int(math.Ceil(float64(stopTime.Nanoseconds())/1000000.0)))
		// 请求的主机
		hostName, err := os.Hostname()
		if err != nil {
			hostName = "unknown"
		}
		// 状态码
		statusCode := c.Writer.Status()
		// 客户端ip
		clientIp := c.ClientIP()
		// 客户端个访问介质 什么浏览器 什么设备
		userAgent := c.Request.UserAgent()
		// 请求文件的长度
		dataSize := c.Writer.Size()
		if dataSize < 0 {
			dataSize = 0
		}
		// 请求的方法
		method := c.Request.Method
		// 请求路径
		path := c.Request.RequestURI
		// 得到对应的字段 （要保存的信息）
		entry := logger.WithFields(logrus.Fields{
			"HostName":  hostName,
			"status":    statusCode,
			"SpendTime": spendTime,
			"Ip":        clientIp,
			"Method":    method,
			"Path":      path,
			"DataSize":  dataSize,
			"Agent":     userAgent,
		})
		// 根据对应的状态码打印对应的日志级别
		if len(c.Errors) > 0 {
			entry.Error(c.Errors.ByType(gin.ErrorTypePrivate).String())
		}
		if statusCode >= 500 {
			entry.Error()
		} else if statusCode >= 400 {
			entry.Warn()
		} else {
			entry.Info()
		}
	}
}
